package com.pine.dcts.websocket;


import com.pine.dcts.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 *  websocket连接调用通用接口类： id为主id type为类型，为WebSocketMessageHandler的实现类的注入spring的实列名
 * @author xiaoyuan
 * @create 2020/10/21 16:26
 **/
@ServerEndpoint("/websocket/{id}/{type}")
@Component
@Slf4j
public class WebSocketHandler implements ApplicationContextAware {

    //concurrent包的线程安全Set，用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    private static Map<String, WebSocketMessageHandler> webSocketMessageHandlerMap = new HashMap<>();

    private ApplicationContext applicationContext;

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "id") String id, @PathParam(value = "type") String type) {
        String key = generateKey(SecurityUtils.getUserId(), id, type);
        sessionPools.put(key, session);
        try {
            sendMessage(session, "已连接成功！");
        } catch (IOException e) {
            log.error("消息发送异常", e);
        }
        WebSocketMessageHandler webSocketMessageHandler = getMessageHandler(type);
        if (webSocketMessageHandler != null)
        {webSocketMessageHandler.init(session, key, id);}
    }

    //发送消息
    public void sendMessage(Session session, String message) throws IOException {
        if (session != null) {
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        }
    }

    //发送消息
    public void sendMessage(String key, String message) {
        Session session = sessionPools.get(key);
        try {
            sendMessage(session, message);
        } catch (IOException e) {
            log.error("消息发送异常", e);
        }
    }

    //关闭连接时调用
    @OnClose
    public void onClose(Session session, @PathParam(value = "id") String id, @PathParam(value = "type") String type) {
        String key = generateKey(SecurityUtils.getUserId(), id, type);
        WebSocketMessageHandler webSocketMessageHandler = getMessageHandler(type);
        if (webSocketMessageHandler != null) {webSocketMessageHandler.close(session, key);}
        sessionPools.remove(generateKey(SecurityUtils.getUserId(), id, type));
    }

    //收到客户端信息
    @OnMessage
    public void onMessage(Session session, String message, @PathParam(value = "id") String id, @PathParam(value = "type") String type) throws IOException {
        WebSocketMessageHandler webSocketMessageHandler = getMessageHandler(type);
        String key = generateKey(SecurityUtils.getUserId(), id, type);
        if (webSocketMessageHandler != null)
        { webSocketMessageHandler.messageHandler(session, key, message);}
    }


    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("websocket调用异常", throwable);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        webSocketMessageHandlerMap = this.applicationContext.getBeansOfType(WebSocketMessageHandler.class);
    }

    private WebSocketMessageHandler getMessageHandler(String type) {
        return webSocketMessageHandlerMap.get(type);
    }

    public static final String generateKey(String userId, String id, String type) {
        return String.format("%s.%s.%s", userId, id, type);
    }
}
